using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class CharacterClass : LoadableJSONObject{
	
	public int level = 0;
	
	public string LevelUp()
	{
		return SetLevel(level+1);
	}
	
	public string SetLevel(int i)
	{
		int levelDif = i - level;
		int startHP = hp;
		int startBAB = GetBAB();
		int startFort = Fortitude;
		int startRef = Reflex;
		int startWill = Will;
		int abilityCount = 0;
		if(i < level)
		{
			while(i < level)
			{
				abilityCount += abilityInstanceTable[level].Count;
				abilityInstanceTable.Remove(level);
				level--;
			}
			
			return 	name + ": Lvl " + (level - levelDif) + " -> " + level + "\n" +
					"     HP Lost: " + (startHP - hp) + "\n" +
					"     BAB Lost: " + (startBAB - GetBAB()) + "\n" +
					"     Fortitude Lost: " + (startFort - Fortitude) + "\n" +
					"     Reflex Lost: " + (startRef - Reflex) + "\n" +
					"     Will Lost: " + (startWill - Will) + "\n" +
					"     " + abilityCount + " Class Abilities Lost \n" + 
					"     Skill Ranks Lost: " + (-levelDif * skillsPerLevel);
		}
		else if(level < i)
		{
			while(i > level)
			{
				level++;
				if(!abilityInstanceTable.ContainsKey(level))
				{
					abilityInstanceTable.Add(level, new List<Ability>());
					
					if(abilityTable.ContainsKey(level))
					{
						foreach(string a in abilityTable[level])
						{
							Ability ab;
							if(FeatManager.index.ContainsKey(a))
								ab = FeatManager.Load(a);
							else
								ab = SpecialAbilityManager.Load(a);
							
							abilityInstanceTable[level].Add(ab);
							abilityCount++;
						}
					}
				}
				else
					abilityCount += abilityInstanceTable[level].Count;
			}
			
			return 	name + ": Lvl " + (level - levelDif) + " -> " + level + "\n" +
					"     HP Gained: " + (hp - startHP) + "\n" +
					"     BAB Gained: " + (GetBAB() - startBAB) + "\n" +
					"     Fortitude Gained: " + (Fortitude - startFort) + "\n" +
					"     Reflex Gained: " + (Reflex - startRef) + "\n" +
					"     Will Gained: " + (Will - startWill) + "\n" +
					"     " + abilityCount + " Class Abilities Gained \n" + 
					"     Skill Ranks Gained: " + (levelDif * skillsPerLevel);
		}
		
		return "";
	}
	
	public int hitDie = 8;
	
	List<int> hpList;
	
	public List<string> classSkills;
	public int skillsPerLevel = 4;
	
	public int hpRandomize
	{
		get
		{
			hpList = null;
			
			return hp;
		}
	}
	
	public int hp
	{
		get
		{
			if(hpList == null)
				hpList = new List<int>{hitDie};
			
			while(hpList.Count > level)
			{
				hpList.RemoveAt(hpList.Count-1);
			}
			
			int l = level;
			
			l -= hpList.Count;
			
			for(int i = 0; i < l; i++)
			{
				hpList.Add(Random.Range(1,hitDie+1));
			}
			
			int h = 0;
			
			foreach(int i in hpList)
			{
				h += i;
			}
			
			return h;
		}
	}
	
	public string BABProgression = "Warrior";
	
	public int GetBAB()
	{
		if(BABProgression == "Warrior")
		{
			return level;
		}
		else if(BABProgression == "Adventurer")
		{
			return Mathf.RoundToInt((3*level)/4);
		}
		return Mathf.FloorToInt(level/2);
	}
	
	public bool FortFavored = true;
	public bool RefFavored = false;
	public bool WillFavored = false;
	
	public int Fortitude
	{
		get
		{
			if(FortFavored)
				return 2 + Mathf.FloorToInt(level/2);
			else
				return Mathf.FloorToInt(level/3);
		}
	}
	
	public int Reflex
	{
		get
		{
			if(RefFavored)
				return 2 + Mathf.FloorToInt(level/2);
			else
				return Mathf.FloorToInt(level/3);
		}
	}
	
	public int Will
	{
		get
		{
			if(WillFavored)
				return 2 + Mathf.FloorToInt(level/2);
			else
				return Mathf.FloorToInt(level/3);
		}
	}
	
	public Dictionary<int,List<string>> abilityTable = new Dictionary<int, List<string>>{};
	
	public List<Ability> Abilities
	{
		get
		{
			List<Ability> a = new List<Ability>();
			for(int i = 1; i <= level; i++)
			{
				if(abilityInstanceTable.ContainsKey(i))
					a.AddRange(abilityInstanceTable[i]);
			}
			return a;
		}
	}
	
	Dictionary<int, List<Ability>> abilityInstanceTable = new Dictionary<int, List<Ability>>{};

	public bool MagicUser = false;
	public bool ArcaneCaster = false;
	
	public SpellsTable spellsPerDay;
	public SpellsTable spellsKnown;
	
	public List<string> spellsUsed = new List<string>{"0","0","0","0","0","0","0","0","0"};
	public List<Spell> SpellsPrepared;
	public List<Spell> SpellsCurrentlyKnown;
	
	public string SpellList = "Sorceror/Wizard";
	public string SpellcastingAbility = "Intelligence";
	
	public CharacterClass()
	{
	}
	
	public override void Load(string json, string file)
	{
		fileName = file;
		Dictionary<string, object> data = MiniJSON.Json.Deserialize(json) as Dictionary<string, object>;
		
		name = data["name"] as string;
		description = data["description"] as string;
		BABProgression = data["BABProgression"] as string;
		level = int.Parse(data["level"] as string);
		hitDie = int.Parse(data["hitDie"] as string);
		
		string hpListJSON = data["hpList"] as string;
		if(!string.IsNullOrEmpty(hpListJSON) && hpListJSON != "null")
		{
			hpList = (MiniJSON.Json.Deserialize(hpListJSON) as List<object>).ConvertAll<int>(o => int.Parse(o as string));
		}
		
		FortFavored = bool.Parse(data["FortFavored"] as string);
		RefFavored = bool.Parse(data["RefFavored"] as string);
		WillFavored = bool.Parse(data["WillFavored"] as string);
		
		abilityTable = new Dictionary<int, List<string>>();
		Dictionary<string,object> abilityDict = MiniJSON.Json.Deserialize(data["abilityTable"] as string) as Dictionary<string,object>;
		foreach(KeyValuePair<string,object> lvl in abilityDict)
		{
			List<string> temp = new List<string>();
			foreach(object a in (lvl.Value as List<object>))
			{
				temp.Add(a as string);
			}
			if(temp.Count > 0)
				abilityTable.Add(int.Parse(lvl.Key), temp);
		}
		
		abilityInstanceTable = new Dictionary<int, List<Ability>>();
		if(data.ContainsKey("abilityInstanceTable"))
		{
			Dictionary<string,object> abilityInstanceDict = MiniJSON.Json.Deserialize(data["abilityInstanceTable"] as string) as Dictionary<string,object>;
			foreach(KeyValuePair<string,object> lvl in abilityInstanceDict)
			{
				List<object> aList = MiniJSON.Json.Deserialize(lvl.Value as string) as List<object>;
				List<Ability> temp = new List<Ability>();
				if(aList != null)
				foreach(object a in aList)
				{
					Ability aLoading = new Ability();
					aLoading.Load(a as string, "");
					temp.Add(aLoading);
				}
				abilityInstanceTable.Add(int.Parse(lvl.Key), temp);
			}
		}
		else
		{
			abilityInstanceTable.Add(1, new List<Ability>());
			
			foreach(string aName in abilityTable[1])
			{
				Ability a;
				if(FeatManager.index.ContainsKey(aName))
					a = FeatManager.Load(aName);
				else
					a = SpecialAbilityManager.Load(aName);	
				abilityInstanceTable[1].Add(a);
			}
		}
		
		
		MagicUser = bool.Parse(data["MagicUser"] as string);
		
		if(data.ContainsKey("ArcaneCaster"))
		{
			ArcaneCaster = bool.Parse(data["ArcaneCaster"] as string);
		}
		
		if(data.ContainsKey("spellsPerDay"))
			spellsPerDay = new SpellsTable(data["spellsPerDay"] as string);
		if(data.ContainsKey("spellsKnown"))
			spellsKnown = new SpellsTable(data["spellsKnown"] as string);
		
		SpellList = data["SpellList"] as string;
		SpellcastingAbility = data["SpellcastingAbility"] as string;
		
		classSkills = new List<string>();
		List<object> skillsListObj = (MiniJSON.Json.Deserialize(data["classSkills"] as string) as List<object>);
		if(skillsListObj != null)
			foreach(object skill in skillsListObj)
			{
				classSkills.Add(skill as string);
			}

		skillsPerLevel = int.Parse(data["skillsPerLevel"]  as string);
		
		if(data.ContainsKey("spellsUsed"))
			spellsUsed = (MiniJSON.Json.Deserialize(data["spellsUsed"] as string) as List<object>).ConvertAll<string>(o => o as string);
		
		if(spellsUsed == null)
			spellsUsed = new List<string>{"0","0","0","0","0","0","0","0","0"};
		
		if(data.ContainsKey("SpellsCurrentlyKnown"))
		{
			List<string> tempList = (MiniJSON.Json.Deserialize(data["SpellsCurrentlyKnown"] as string) as List<object>).ConvertAll<string>(o => o as string);
			if(tempList != null)
				SpellsCurrentlyKnown = tempList.ConvertAll<Spell>(j => {Spell s = new Spell(); s.Load(j, j); return s;});
		}
		else if(MagicUser)
			SpellsCurrentlyKnown = new List<Spell>();
		
		if(data.ContainsKey("SpellsPrepared"))
		{
			List<string> tempList = (MiniJSON.Json.Deserialize(data["SpellsPrepared"] as string) as List<object>).ConvertAll<string>(o => o as string);
			if(tempList != null)	
				SpellsPrepared = tempList.ConvertAll<Spell>(j => {Spell s = new Spell(); s.Load(j, j); return s;});
		}
		else if(MagicUser)
			SpellsPrepared = new List<Spell>();
	}
	
	public override string ToJSON()
	{
		Dictionary<string,string> data = new Dictionary<string, string>();
		
		data.Add("name", name.ToString());
		data.Add("description", description.ToString());
		data.Add("BABProgression", BABProgression.ToString());
		data.Add("level", level.ToString());
		data.Add("hitDie", hitDie.ToString());
		
		if(hpList == null)
		{
			hpList = new List<int>{hitDie};
		}
		
		data.Add("hpList", MiniJSON.Json.Serialize(hpList));
		data.Add("FortFavored", FortFavored.ToString());
		data.Add("RefFavored", RefFavored.ToString());
		data.Add("WillFavored", WillFavored.ToString());
		data.Add("MagicUser", MagicUser.ToString());
		data.Add("ArcaneCaster", ArcaneCaster.ToString());
		
		if(spellsPerDay != null)
			data.Add("spellsPerDay", spellsPerDay.ToJSON());
		if(spellsKnown != null)
			data.Add("spellsKnown", spellsKnown.ToJSON());
		
		data.Add("SpellList", SpellList.ToString());
		data.Add("SpellcastingAbility", SpellcastingAbility.ToString());
		data.Add("classSkills", MiniJSON.Json.Serialize(classSkills));
		data.Add("skillsPerLevel", skillsPerLevel.ToString());
		
		Dictionary<string, List<string>> abilityDict = new Dictionary<string, List<string>>();
		foreach(KeyValuePair<int, List<string>> lvl in abilityTable)
		{
			abilityDict.Add(lvl.Key.ToString(), lvl.Value);
		}
		data.Add("abilityTable", MiniJSON.Json.Serialize(abilityDict));
		
		Dictionary<string, string> abilityInstanceDict = new Dictionary<string, string>();
		foreach(KeyValuePair<int, List<Ability>> lvl in abilityInstanceTable)
		{
			abilityInstanceDict.Add(lvl.Key.ToString(), lvl.Value.ToJSON());
		}
		data.Add("abilityInstanceTable", MiniJSON.Json.Serialize(abilityInstanceDict));
		
		data.Add("spellsUsed", MiniJSON.Json.Serialize(spellsUsed));
		
		if(SpellsPrepared != null)
			data.Add("SpellsPrepared", MiniJSON.Json.Serialize(SpellsPrepared.ConvertAll<string>(spell => spell.ToJSON())));
		if(SpellsCurrentlyKnown != null)
			data.Add("SpellsCurrentlyKnown", MiniJSON.Json.Serialize(SpellsCurrentlyKnown.ConvertAll<string>(spell => spell.ToJSON())));
		
		return MiniJSON.Json.Serialize(data);
	}
	
	public CharacterClass DeepCopy()
	{
		CharacterClass a = new CharacterClass();
		a.Load(ToJSON(), fileName);
		return a;
	}
	
}
